<?php
/*
 * 将整数字符串转成整数值
 * 【题目】
 * 给定一个字符串str，如果str符合日常书写的整数形式，并且属于32位整数的范围，返回str所代表的整数值，否则返回0。
 * 【举例】
 * str="123"，返回123。
 * str="023"，因为"023"不符合日常的书写习惯，所以返回0。
 * str="A13"，返回0。
 * str="0"，返回0。
 * str="2147483647"，返回2147483647。
 * str="2147483648"，因为溢出了，所以返回0。
 * str="-123"，返回-123
 */

$arr = ['123', '-', '-1', '-0', '033', PHP_INT_MIN, PHP_INT_MIN-1, PHP_INT_MAX, PHP_INT_MAX+1];
$obj = new Code_02_ConvertString2Num();
$obj->main($arr);

class Code_02_ConvertString2Num
{
    public function main($arr)
    {
        foreach ($arr as $str) {
            echo 'str = '.$str;
            $res = intval($this->convert($str));
            echo ' res = '.$res . PHP_EOL;
        }
    }

    protected function convert($str)
    {
        if ($str === null || $str === '') {
            return 0; // can not convert
        }
        $chas = str_split($str);
		if (!$this->_isValid($chas)) {
            return 0; // can not convert
        }
        $positive = $chas[0] == '-' ? false : true; //判断正负
		$minq = intval(PHP_INT_MIN / 10);   //系统最小值 除以 10的结果
		$minr = PHP_INT_MIN % 10;               //系统最小值 模 10的结果
		$res = 0;
        for ($i = $positive ? 0 : 1; $i < count($chas); $i++) {
            //由于负数的最小值的绝对值范围都比正数的最大值的绝对值范围要大，所以统一从负数来处理
            $cur = ord('0') - ord($chas[$i]);
            // 必须先于res来判断是否越界
            if (
                ($res < $minq)      // 当前结果小于【系统最小值 除以 10的结果】，下面乘以10必定溢出，返回False
                ||
                ($res == $minq && $cur < $minr) // 当前结果==【系统最小值 除以 10的结果】，但加上最后一位小于【系统最小值 模 10的结果】的话，还是会溢出
            ) {
                return 0; // can not convert
            }
            $res = $res * 10 + $cur;
        }
        // 如果是正数 但res==系统最小值也依然不能转
		if ($positive && $res == PHP_INT_MIN) {
            return 0; // can not convert
        }
		return $positive ? -$res : $res;
    }

    protected function _isValid($chas)
    {
        // 正数+首字符不是0-9 => false
        if ($chas[0] != '-' && (ord($chas[0]) < ord('0') || ord($chas[0]) > ord('9'))) {
            return false;
        }
        // 只有负数符号或者str=-0 => false
        if ($chas[0] == '-' && (count($chas) == 1 || $chas[1] == '0')) {
            return false;
        }
        // 长度大于1且首字符为0
        if ($chas[0] == '0' && count($chas) > 1) {
            return false;
        }
        // 判断ascii码
        for ($i = 1; $i < count($chas); $i++) {
            if (ord($chas[$i]) < ord('0') || ord($chas[$i]) > ord('9')) {
                return false;
            }
        }
		return true;
    }
}